package com.example.tbplus14.utils.html;

import com.example.tbplus14.enums.InspectionHazardEnum;
import com.example.tbplus14.utils.MyChartUtils;
import gui.ava.html.parser.HtmlParser;
import gui.ava.html.parser.HtmlParserImpl;
import gui.ava.html.renderer.ImageRenderer;
import gui.ava.html.renderer.ImageRendererImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.util.Matrix;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.DefaultDrawingSupplier;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.RingPlot;
import org.jfree.chart.ui.RectangleInsets;
import org.jfree.data.general.DefaultPieDataset;
import org.springframework.core.io.ClassPathResource;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.*;


@Slf4j
public class Html2PDF2Test {

    public static final String RESOURCE_PATH = "/";


    public static void main(String[] args) throws Exception{
        htmlToImg(null);

        Map<String, Double> map = new LinkedHashMap<>();
        map.put("苹果", 2000.0);
        map.put("香蕉", 440.0);
        map.put("橘子", 2515.0);
        map.put("梨", 1500.0);

        ClassPathResource imgBaseUrl = new ClassPathResource(RESOURCE_PATH);
        String imgPath = imgBaseUrl.getURL().getPath();
        // 饼图
        String img1 = MyChartUtils.createPiePort("水果比例", map, imgPath + "bingtu.png", 246, 122);
        // 环形图
        String img2 = MyChartUtils.createCircularChart("水果比例", map, imgPath + "huantu.png", 246, 122);

        ClassPathResource pdfResource = new ClassPathResource(RESOURCE_PATH);
        String pdfPath = pdfResource.getURL().getPath() + "percentage.pdf";

        Map<String, String> descMap = new LinkedHashMap<>();
        descMap.put(InspectionHazardEnum.ALL_COUNT.getValue(), "19");
        // 严重
        descMap.put(InspectionHazardEnum.SERIOUS.getValue(), "5");
        descMap.put(InspectionHazardEnum.HIGH.getValue(), "3");
        descMap.put(InspectionHazardEnum.MEDIUM.getValue(), "2");
        descMap.put(InspectionHazardEnum.LOW.getValue(), "1");
        descMap.put(InspectionHazardEnum.COMPANY.getValue(), "内蒙古昆明卷烟有限责任公司");
        descMap.put(InspectionHazardEnum.RATING.getValue(), "高危不安全系统");
        createPdf(Arrays.asList(img1, img2), pdfPath, descMap);

    }


    /**
     * 给字符串数值填充空格，以保证生成pdf文件排版不会乱
     */
    private static String handlerValue(String value){
        int length = value.length();
        if (length % 2 == 0){
            if (length == 2){
                return String.format("  %s ", value);
            }
            if (length == 4){
                return String.format(" %s", value);
            }
        }else{
            if (length == 1){
                return String.format("  %s  ", value);
            }
            if (length == 3){
                return String.format(" %s ", value);
            }
        }
        return value;
    }


    public static void createPdf(List<String> imgPath, String savePath, Map<String, String> descriptiveMap) {
        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage();
            document.addPage(page);


            // 加载字体位置
            ClassPathResource pdfResource = new ClassPathResource(RESOURCE_PATH);
            String fontPath = pdfResource.getURL().getPath() + File.separator + "static/font/msyh.TTF";

            // 哪些不需要拼接逗号
            List<String> noHasCommaList = new ArrayList<>();
            noHasCommaList.add(InspectionHazardEnum.RATING.getValue());
            noHasCommaList.add(InspectionHazardEnum.COMPANY.getValue());

            String comma = ", ";
            String before = "本次测试共发现";

            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                File fontFile = new File(fontPath);
                PDType0Font font = PDType0Font.load(document, fontFile);

                // 设置页面边距和宽度
                float margin = 60;
                int fontSize = 12;
                float width = page.getMediaBox().getWidth() - 2 * margin;
                float startY = page.getMediaBox().getHeight() - margin;

                // 设置字体和颜色
                contentStream.beginText();
                contentStream.setFont(font, fontSize);
                contentStream.setLeading(14.5f); // 设置行间距
                contentStream.newLineAtOffset(margin + fontSize * 2, startY);

                // 前缀
                contentStream.showText(before);
                // 判断第一行 做前空两个换行处理
                boolean flagFirst = true;
                // 处理换行
                StringBuilder row = new StringBuilder();
                for (Map.Entry<String, String> entry : descriptiveMap.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    // 设置字体颜色
                    InspectionHazardEnum.setColor(key, contentStream);
                    // 不同等级漏洞个数描述
                    String desc = String.format(InspectionHazardEnum.desc(key), handlerValue(value));

                    StringBuilder line = new StringBuilder();
                    String[] words = desc.split("");
                    for (String word : words) {
                        float rowWidth = font.getStringWidth(row.toString()) / 1000 * fontSize;
                        float lineWidth = font.getStringWidth(line.toString()) / 1000 * fontSize;
                        float wordWidth = font.getStringWidth(word) / 1000 * fontSize;
                        // 当前行已经填充字符 + 预计填充字符 < 行容纳字符
                        // 当前行已经填充字符 + 预计填充字符 * 2 < 行容纳字符 第一行开头空两格
                        // 第一行，空两格
                        if (flagFirst){
                            if (lineWidth + wordWidth < width && rowWidth - fontSize * 10 < width) {
                                line.append(word);
                                row.append(word);
                                if (!noHasCommaList.contains(key)){
                                    row.append(comma);
                                }
                            } else {
                                contentStream.showText(line.toString());
                                contentStream.newLineAtOffset(-fontSize * 2, -25);
                                flagFirst = false;
                                line = new StringBuilder(word);
                                row = new StringBuilder(word);
                            }
                        }else{
                            if (lineWidth + wordWidth < width && rowWidth - fontSize * 2 < width) {
                                line.append(word);
                                row.append(word);
                                if (!noHasCommaList.contains(key)){
                                    row.append(comma);
                                }
                            } else {
                                contentStream.showText(line.toString());
                                contentStream.newLineAtOffset(0, -25);
                                line = new StringBuilder(word);
                                row = new StringBuilder(word);
                            }
                        }

                    }
                    contentStream.showText(line.toString());
                    InspectionHazardEnum.setColor(null, contentStream);
                    if (!noHasCommaList.contains(key)){
                        contentStream.showText(comma);
                    }
                }

                contentStream.endText();

                // 添加图片
                PDImageXObject pdImage = PDImageXObject.createFromFile(imgPath.get(0), document);
                contentStream.drawImage(pdImage, margin, 50); // 图片位置调整

                // "图1-1" 图例描述
                setImgDesc(contentStream, fontSize, font, "图1-1 水果比例");

                PDImageXObject pdImage1 = PDImageXObject.createFromFile(imgPath.get(1), document);
                contentStream.drawImage(pdImage1, margin, 300); // 图片位置调整

                // 水印
                setWatermark(contentStream, fontSize, font, "创联致信");
            }

            document.save(savePath);
            document.close();
            log.info("createPdf-imgPath:{}", imgPath);
            log.info("createPdf-pdfPath:{}", savePath);
        } catch (IOException e) {
            log.error("创建pdf文件异常", e);
            throw new RuntimeException("创建pdf文件异常");
        }
    }

    private static void setImgDesc(PDPageContentStream contentStream
            , int fontSize, PDType0Font font, String desc) throws IOException{
        contentStream.beginText();
        contentStream.setFont(font, fontSize - 4);
        contentStream.newLineAtOffset(280, 292);
        contentStream.showText(desc);
        contentStream.endText();
    }

    /**
     * 设置水印
     * @param contentStream
     * @param fontSize
     * @param font
     * @throws IOException
     */
    private static void setWatermark(PDPageContentStream contentStream
            , int fontSize, PDType0Font font, String watermarkText) throws IOException{
        String ts = watermarkText;
        PDExtendedGraphicsState r0 = new PDExtendedGraphicsState();
        // 透明度
        r0.setNonStrokingAlphaConstant(0.4f);
        r0.setAlphaSourceFlag(true);
        contentStream.setGraphicsStateParameters(r0);
        contentStream.setNonStrokingColor(220,220,220);
        contentStream.beginText();
        contentStream.setFont(font, fontSize * 6);
        // 获取旋转实例
        contentStream.setTextMatrix(Matrix.getRotateInstance(45,240f,520f));
        contentStream.showText(ts);
        contentStream.endText();
        // 透明度还原
        PDExtendedGraphicsState r1 = new PDExtendedGraphicsState();
        r1.setNonStrokingAlphaConstant(1.0f);
        r1.setAlphaSourceFlag(true);
        contentStream.setGraphicsStateParameters(r1);
        // 还原字体颜色
        InspectionHazardEnum.setColor(null, contentStream);
    }


    /**
     * 画echarts图
     * @param percentage 饼图数据
     * @param title 标题
     * @return 保存路径
     */
    @SuppressWarnings("all")
    private static String echartsToImg(Map<String, Double> percentage, String title, String type){
        DefaultPieDataset dataset = new DefaultPieDataset();
        for (Map.Entry<String, Double> entry : percentage.entrySet()) {
            dataset.setValue(entry.getKey(), entry.getValue());
        }

        // 创建主题样式
        StandardChartTheme standardChartTheme = new StandardChartTheme("CN");
        // 设置标题字体
        standardChartTheme.setExtraLargeFont(new Font("宋体", Font.BOLD, 12));
        // 设置图例的字体
        standardChartTheme.setRegularFont(new Font("宋体", Font.BOLD, 12));
        // 设置轴向的字体
        standardChartTheme.setLargeFont(new Font("宋体", Font.BOLD, 10));
        // 设置主题背景色
        standardChartTheme.setChartBackgroundPaint(Color.WHITE);
        // 应用主题样式
        ChartFactory.setChartTheme(standardChartTheme);

        JFreeChart chart;
        if ("h".equals(type)){
            chart = ChartFactory.createRingChart(title, dataset, true, false, false);

            RingPlot ringplot = (RingPlot) chart.getPlot();
            ringplot.setOutlineVisible(false);
            //{2}表示显示百分比  //{0}:key {1}:value {2}:百分比 {3}:sum
            ringplot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}:{1}"));
            ringplot.setBackgroundPaint(new Color(253, 253, 253));
            ringplot.setOutlineVisible(false);
            ringplot.setLabelFont(new Font("宋体", Font.BOLD, 15));
            ringplot.setSeparatorsVisible(false);
            ringplot.setSeparatorPaint(Color.WHITE);
            ringplot.setShadowPaint(new Color(253, 253, 253));
            // 设置深度，即带颜⾊圆环的宽度
            ringplot.setSectionDepth(0.4);
            ringplot.setStartAngle(90);
            // 指定颜色
            ringplot.setDrawingSupplier(new DefaultDrawingSupplier(
                    new Paint[] {
                            new Color(46, 199, 201),
                            new Color(182, 162, 222),
                            new Color(90, 177, 239),
                            new Color(255, 185, 128),
                            new Color(226, 117, 123)
                    },
                    DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE,
                    DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
                    DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
                    DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE));
        }else{
            chart = ChartFactory.createPieChart(
                    title,               // 图表标题
                    dataset,             // 数据集
                    true,                // 显示图例
                    true,                // 使用 tooltips
                    false                // 不生成 URL 链接
            );

            // 配置外观
            PiePlot plot = (PiePlot) chart.getPlot();
            // 白色背景
            plot.setBackgroundPaint(Color.WHITE);
            // 背景边框色
            plot.setOutlinePaint(Color.lightGray);
            plot.setCircular(true);
            plot.setLabelGap(0.02);
        }

        // 设置边距与图表边界
        chart.setPadding(new RectangleInsets(10, 10, 10, 10));
        // 图例位置在右侧
        // chart.getLegend().setPosition(RectangleEdge.RIGHT);

        // 保存图表为PNG图片文件
        try {
            int width = 500;  // 图片宽度
            int height = 240; // 图片高度
            ClassPathResource imgPath = new ClassPathResource(RESOURCE_PATH);
            String path = imgPath.getURL().getPath() + File.separator + String.format("%stest.png", type);
            File chartFile = new File(path);
            ChartUtils.saveChartAsPNG(chartFile, chart, width, height);
            log.info("echarts保存为图片路径{}", path);
            return path;
        } catch (IOException e) {
            log.error("echarts保存为图片异常", e);
            throw new RuntimeException("echarts保存为图片异常");
        }
    }


    /**
     * 弃用版本
     */
    @Deprecated
    public static void createPdf1(String imgPath, String savePath, Map<String, String> descriptiveMap) {
        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage();
            document.addPage(page);

            // 加载字体位置
            ClassPathResource pdfResource = new ClassPathResource(RESOURCE_PATH);
            String fontPath = pdfResource.getURL().getPath() + File.separator + "static/font/msyh.TTF";

            String text = "春天到了，老师带我们去郊外春游。一大早，我就背着装满零食的书包来到学校，和同学们一起坐上大巴车。路上，大家唱着歌，看着窗外飞快掠过的树木，心情特别激动。到了目的地，眼前是一片绿油油的草地，五颜六色的小花点缀其间。我和小伙伴们在草地上奔跑，追逐着翩翩起舞的蝴蝶。中午，我们围坐在一起野餐，分享各自带来的美食，你吃我的饼干，我尝你的水果，欢声笑语不断。下午，老师带我们玩老鹰捉小鸡的游戏，我紧紧抓住前面同学的衣服，生怕被“老鹰”捉到。太阳快要落山时，我们依依不舍地踏上归途。这次春游让我感受到了大自然的美丽，也体会到了和同学们在一起的快乐，这真是难忘的一天";

            String before = "本次测试共发现";
            Map<String, String> descMap = new LinkedHashMap<>();
            descMap.put(InspectionHazardEnum.ALL_COUNT.getValue(), "10");
            // 严重
            descMap.put(InspectionHazardEnum.SERIOUS.getValue(), "5");
            descMap.put(InspectionHazardEnum.HIGH.getValue(), "3");
            descMap.put(InspectionHazardEnum.MEDIUM.getValue(), "2");
            descMap.put(InspectionHazardEnum.LOW.getValue(), "0");
            descMap.put(InspectionHazardEnum.RATING.getValue(), "高危不安全系统");


            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                File fontFile = new File(fontPath);
                PDType0Font font = PDType0Font.load(document, fontFile);

                // 设置页面边距和宽度
                float margin = 60;
                int fontSize = 12;
                float width = page.getMediaBox().getWidth() - 2 * margin;
                float startY = page.getMediaBox().getHeight() - margin;

                // 设置字体和颜色
                contentStream.beginText();
                contentStream.setFont(font, fontSize);
                contentStream.setLeading(14.5f); // 设置行间距
//                contentStream.setNonStrokingColor(255, 0, 0); // 设置颜色为红色
                contentStream.newLineAtOffset(margin + fontSize * 2, startY);

                // 前缀
                int index = before.length();
                contentStream.showText(before);
                boolean flogFirst = true;
                for (Map.Entry<String, String> entry : descMap.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (flogFirst){
                        contentStream.newLineAtOffset(margin + fontSize * 2 + index * fontSize, startY);
                        flogFirst = false;
                    }
                    // 不同等级漏洞个数描述
                    String desc = String.format(InspectionHazardEnum.desc(key), value);
                    String[] words = desc.split("");
                    StringBuilder line = new StringBuilder();
                    for (String word : words) {
                        float lineWidth = font.getStringWidth(line.toString()) / 1000 * fontSize;
                        float wordWidth = font.getStringWidth(word) / 1000 * fontSize;
                        if (lineWidth + wordWidth < width && lineWidth + wordWidth * 2 <= width) {
                            line.append(word);
                        } else {
                            contentStream.showText(line.toString());
                            contentStream.newLineAtOffset(0, -25);
                            line = new StringBuilder(word);
                        }
                    }

                    contentStream.setNonStrokingColor(0, 0, 0); // 设置颜色为黑色
                    contentStream.showText(before);

                    contentStream.setNonStrokingColor(0, 0, 0); // 设置颜色为黑色

                }
                // 自动换行处理
                String[] words = text.split("");
                StringBuilder line = new StringBuilder();
                // 首行空两格处理
                boolean flagIndentation = true;
                for (String word : words) {
                    float lineWidth = font.getStringWidth(line.toString()) / 1000 * fontSize;
                    float wordWidth = font.getStringWidth(word) / 1000 * fontSize;

                    if (flagIndentation){
                        if (lineWidth + wordWidth < width - wordWidth * 2) {
                            line.append(word);
                        } else {
                            flagIndentation = false;
                            String str = line.toString();
                            String s = "装满零食";
//                            if (str.contains(s)){
//                                String start = str.substring(0, str.indexOf(s));
//                                contentStream.showText(start);
//                                contentStream.setNonStrokingColor(255, 0, 0); // 设置颜色为红色
//                                contentStream.showText(s);
//                                contentStream.setNonStrokingColor(0, 0, 0); // 设置颜色为黑色
//                                String end = str.substring(str.indexOf(s) + s.length());
//                                contentStream.showText(end);
//                            }else{
//                            }
                                contentStream.showText(line.toString());
                            contentStream.newLineAtOffset(- fontSize * 2, -25);
                            line = new StringBuilder(word);
                        }
                    }else{
                        if (lineWidth + wordWidth < width && lineWidth + wordWidth * 2 <= width) {
                            line.append(word);
                        } else {
                            contentStream.showText(line.toString());
                            contentStream.newLineAtOffset(0, -25);
                            line = new StringBuilder(word);
                        }
                    }
                }

                // 写入最后一行
                if (line.length() > 0) {
                    contentStream.showText(line.toString());
                }

                contentStream.endText();

                // 添加图片
                PDImageXObject pdImage = PDImageXObject.createFromFile(imgPath, document);
                contentStream.drawImage(pdImage, margin, 250); // 图片位置调整
            }

            document.save(savePath);
            document.close();
            log.info("imgPath:{}", imgPath);
            log.info("pdfPath:{}", savePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }




    public static String htmlToImg(String cardPath) {
        try {
            HtmlParser htmlParser = new HtmlParserImpl();
//            ClassPathResource classPathResource = new ClassPathResource(String.format("%test.png.png", RESOURCE_PATH));
//            String cardPath = classPathResource.getURL().getPath();

            String HtmlTemplateStr = "<div style=\"width: 100%;\">\n" +
                    "    <table style=\"border: 1px solid black;\">\n" +
                    "        <tr>\n" +
                    "            <th>标题1</th>\n" +
                    "            <th>标题2</th>\n" +
                    "        </tr>\n" +
                    "        <tr>\n" +
                    "            <td>数据1</td>\n" +
                    "            <td>数据2</td>\n" +
                    "        </tr>\n" +
                    "    </table>\n" +
                    "</div>";
            htmlParser.loadHtml(HtmlTemplateStr);
            ImageRenderer imageRenderer = new ImageRendererImpl(htmlParser);
//            imageRenderer.setWidth(200);
            ClassPathResource imgPath = new ClassPathResource(RESOURCE_PATH);
            String path = imgPath.getURL().getPath() + File.separator + "testAll.png";
            imageRenderer.saveImage(path);
            imageRenderer.clearCache();
            return path;
        } catch (Exception e) {
            log.error("html转img异常", e);
        }
        return null;
    }

    private static File imgToPdf(String imgPath, String fileName){
        try (PDDocument document = new PDDocument()) {
            // 找到pdf存放位置绝对路径
            ClassPathResource pdfResource = new ClassPathResource(RESOURCE_PATH);
            String pdfPath = pdfResource.getURL().getPath() + fileName;
            // 创建新页面
            PDPage page = new PDPage();
            document.addPage(page);
            // 加载图片
            PDImageXObject image = PDImageXObject.createFromFile(imgPath, document);
            float width = image.getWidth();
            float height = image.getHeight();
            // 设置最大宽度
            float maxWidth = 500;
            // 设置最大高度
            float maxHeight= 1000;
            // 计算缩放比例
            float scale = Math.min(maxWidth / width, maxHeight / height);
            // 计算缩放后的宽度
            float scaledwidth = width * scale;
            // 计算缩放后的高度
            float scaledHeight = height * scale;
            try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
                // 将图片添加到页面
                contentStream.drawImage(image,100,260, scaledwidth, scaledHeight);
            }
            // 保存 PDF 文件
            File file = new File(pdfPath);
            document.save(file);
            return file;
        }catch (IOException e) {
            log.error("vca账户下载pdf文件异常", e);
            throw new RuntimeException("Download failed, please try again later");
        }
    }




}
